//  Copyright (c) 2008  Yoong-ki Ahn & Youngjin Kim < mexif@googlegroups.com>
//  See the enclosed file COPYING for license information (MIT Licence).
//  If you did not receive this file,
//  see http://www.opensource.org/licenses/mit-license.php.

#ifndef __MEXIF_DEF_H__
#define __MEXIF_DEF_H__

#ifdef __cplusplus
extern "C"
{
#endif

typedef enum
{
	MEXIF_RET_OK			= 0,
	MEXIF_RET_ERROR			= 1,
	MEXIF_RET_CORRUPT_DATA	= 2,
	MEXIF_RET_MISSING_EXIF_HEADER = 3,
	MEXIF_RET_MISSING_TIFF_HEADER = 4,
} mexif_return_t;

typedef enum 
{
	MEXIF_VALUE_BYTE		= 1,
	MEXIF_VALUE_ASCII		= 2,	///< null terminated.
	MEXIF_VALUE_UINT16		= 3,    ///< uint16
	MEXIF_VALUE_UINT32		= 4,	///< uint32
	MEXIF_VALUE_RATIONAL	= 5,	///< uint32 / uint32
	MEXIF_VALUE_SINT8		= 6,
	MEXIF_VALUE_UNDEFINED	= 7,	///< byte array.
	MEXIF_VALUE_SINT16		= 8,	///< int16
	MEXIF_VALUE_SINT32		= 9,	///< int32
	MEXIF_VALUE_SRATIONAL	= 10,	///< int32 / int32
} mexif_value_t;

/// welknown section.
typedef enum
{
	MEXIF_SECTION_UNKNOWN	= 0,
	MEXIF_SECTION_0			= 1,		///< main image ifd
	MEXIF_SECTION_1			= 2,		///< thumbnail ifd
	MEXIF_SECTION_EXIF		= 3,		///< exif ifd
	MEXIF_SECTION_GPS		= 4,		///< gps ifd
	MEXIF_SECTION_INTEROP	= 5,		///< interoperability ifd
	MEXIF_SECTION_MAKERNOTE	= 6,		///< maker note.
	_MEXIF_SECTION_COUNT	= 7,
} mexif_section_type_t;

#ifdef _MEXIFLIB_INSIDE
/// normal dll exports only a function.
extern mexif_pcstr mexif_section_type_str[_MEXIF_SECTION_COUNT];
#endif
mexif_pcstr MEXIF_API mexif_get_section_type_str( mexif_uint32 ui );


typedef enum
{
	MEXIF_BASE_FORMAT_IFD		= 1,
	MEXIF_BASE_FORMAT_U8ARRAY	= 2,
	MEXIF_BASE_FORMAT_U16ARRAY	= 3,
	MEXIF_BASE_FORMAT_U32ARRAY	= 4,
} mexif_base_format_t;

#define MEXIF_MAKE_FORMAT( base, index )	((base-1)<<24) | (index)
#define MEXIF_GET_BASE_FORMAT( fmt )		(((fmt>>24)&0xff) +1)

/// section format.
typedef enum
{
	MEXIF_FORMAT_UNKNOWN				= 0,
	MEXIF_FORMAT_EXIF_IFD				= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 1 ),
	MEXIF_FORMAT_GPS_IFD				= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 2 ),
	MEXIF_FORMAT_INTEROP_IFD			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 3 ),
	MEXIF_FORMAT_CANON_IFD				= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 4 ),
	MEXIF_FORMAT_CASIO1_IFD				= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 5 ),
	MEXIF_FORMAT_CASIO2_IFD				= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 6 ),
	MEXIF_FORMAT_FUJIFILM_IFD			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 7 ),
	MEXIF_FORMAT_KONICA_IFD				= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 8 ),
	MEXIF_FORMAT_MINOLTA_IFD			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 9 ),
	MEXIF_FORMAT_NIKON1_IFD				= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 0x0a ),
	MEXIF_FORMAT_NIKON2_IFD				= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 0x0b ),
	MEXIF_FORMAT_OLYMPUS_IFD			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 0x0c ),
	MEXIF_FORMAT_PANASONIC1_IFD			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 0x0d ),
	MEXIF_FORMAT_PENTAX1_IFD			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 0x0e ),
	MEXIF_FORMAT_PENTAX2_IFD			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 0x0f ),
	MEXIF_FORMAT_POLAROID_IFD			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 0x10 ),
	MEXIF_FORMAT_RICOH_IFD				= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 0x11 ),
	MEXIF_FORMAT_SAMSUNG_IFD			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 0x12 ),
	MEXIF_FORMAT_SANYO_IFD				= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 0x13 ),
	MEXIF_FORMAT_SHARP_IFD				= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 0x14 ),
	MEXIF_FORMAT_SIGMA_IFD				= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 0x15 ),
	MEXIF_FORMAT_SONY_IFD				= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 0x16 ),
	MEXIF_FORMAT_TOSHIBA_IFD			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD, 0x17 ),

	MEXIF_FORMAT_CANON_CameraSettings	= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U16ARRAY, 0x0400 ),
	MEXIF_FORMAT_CANON_FocalLength		= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U16ARRAY, 0x0401 ),
	MEXIF_FORMAT_CANON_ShotInfo			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U16ARRAY, 0x0402 ),
	MEXIF_FORMAT_CANON_Panorama			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U16ARRAY, 0x0403 ),
	MEXIF_FORMAT_CANON_AFInfo			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U16ARRAY, 0x0404 ),
	MEXIF_FORMAT_CANON_MyColors			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U16ARRAY, 0x0405 ),
	MEXIF_FORMAT_CANON_FaceDetect1		= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U16ARRAY, 0x0406 ),
	MEXIF_FORMAT_CANON_FaceDetect2		= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U8ARRAY,  0x0407 ),
	MEXIF_FORMAT_CANON_AFInfo2			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U16ARRAY, 0x0408 ),
	MEXIF_FORMAT_CANON_FileInfo			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U16ARRAY, 0x0409 ),
	MEXIF_FORMAT_CANON_ProcessingInfo	= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U16ARRAY, 0x040a ),
	MEXIF_FORMAT_CANON_SensorInfo		= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U16ARRAY, 0x040b ),
	MEXIF_FORMAT_CANON_ColorInfo		= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U16ARRAY, 0x040c ),

	MEXIF_FORMAT_MINOLTA_CameraSettings     = MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U32ARRAY, 0x0901 ),
	MEXIF_FORMAT_MINOLTA_CameraSettings7D   = MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U16ARRAY, 0x0902 ),
	MEXIF_FORMAT_MINOLTA_CameraSettings5D   = MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U16ARRAY, 0x0903 ),
	MEXIF_FORMAT_MINOLTA_CameraSettingsA100 = MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U16ARRAY, 0x0904 ),

	MEXIF_FORMAT_NIKON1_PreviewImage	= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD,		 0x0a01 ),
	MEXIF_FORMAT_NIKON1_AFInfo			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U8ARRAY,	 0x0a02 ),

	MEXIF_FORMAT_OLYMPUS_Equipment			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD,		 0x0c01 ),
	MEXIF_FORMAT_OLYMPUS_CameraSettings		= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD,		 0x0c02 ),
	MEXIF_FORMAT_OLYMPUS_FocusInfo			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_IFD,		 0x0c03 ),

	MEXIF_FORMAT_PENTAX1_ShakeReductionInfo	= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U8ARRAY,	 0x0e01 ),
	MEXIF_FORMAT_PENTAX1_ShotInfo			= MEXIF_MAKE_FORMAT( MEXIF_BASE_FORMAT_U8ARRAY,	 0x0e02 ),


	_MEXIF_FORMAT_COUNT
} mexif_format_t;

typedef enum
{
	MEXIF_SUBSECTION_UNKNOWN	= 0,
} mexif_subsection_type_t;

/// welknown maker.
typedef enum 
{
	MEXIF_MAKER_UNKNOWN,
	MEXIF_MAKER_AGFA,
	MEXIF_MAKER_CANON,
	MEXIF_MAKER_CASIO,
	MEXIF_MAKER_EPSON,
	MEXIF_MAKER_FUJIFILM,
	MEXIF_MAKER_KODAK,
	MEXIF_MAKER_KONICA,
	MEXIF_MAKER_MINOLTA,
	MEXIF_MAKER_KYOCERA,
	//MEXIF_MAKER_CONTAX,
	MEXIF_MAKER_NIKON,
	MEXIF_MAKER_OLYMPUS,
	MEXIF_MAKER_PANASONIC,
	MEXIF_MAKER_PENTAX,
	MEXIF_MAKER_POLAROID,
	//MEXIF_MAKER_ASAHI,
	MEXIF_MAKER_RICOH,
	MEXIF_MAKER_SAMSUNG,
	MEXIF_MAKER_SANYO,
	MEXIF_MAKER_SIGMA,
	MEXIF_MAKER_SHARP,
	MEXIF_MAKER_SONY,
	MEXIF_MAKER_TOSHIBA,
	_MEXIF_MAKER_COUNT,
} mexif_maker_t;

#ifdef _MEXIFLIB_INSIDE
extern mexif_pcstr	mexif_maker_str[_MEXIF_MAKER_COUNT];
#endif // _MEXIFLIB_INSIDE
mexif_pcstr	MEXIF_API mexif_get_maker_str( mexif_uint32 ui );

/// welknown makernote type.
typedef enum 
{
	MEXIF_MAKERNOTE_UNKNOWN,
	MEXIF_MAKERNOTE_CANON,
	MEXIF_MAKERNOTE_CASIO1,
	MEXIF_MAKERNOTE_CASIO2,
	MEXIF_MAKERNOTE_FUJIFILM,
	MEXIF_MAKERNOTE_PANASONIC1,
	MEXIF_MAKERNOTE_NIKON1,
	MEXIF_MAKERNOTE_NIKON2,
	MEXIF_MAKERNOTE_PENTAX1,
	MEXIF_MAKERNOTE_PENTAX2,
	MEXIF_MAKERNOTE_RICOH,
	MEXIF_MAKERNOTE_SANYO,
	MEXIF_MAKERNOTE_SIGMA,
	MEXIF_MAKERNOTE_SONY,

	MEXIF_MAKERNOTE_AGFA,
	MEXIF_MAKERNOTE_EPSON,
	MEXIF_MAKERNOTE_KONICA,
	MEXIF_MAKERNOTE_MINOLTA,
	MEXIF_MAKERNOTE_KYOCERA,
	MEXIF_MAKERNOTE_CONTAX,
	MEXIF_MAKERNOTE_OLYMPUS,
	MEXIF_MAKERNOTE_ASAHI,
	MEXIF_MAKERNOTE_SAMSUNG,
} mexif_makernote_t;

/// some fucking model needs specialized code.
typedef enum 
{
	// normal model.
	MEXIF_MODEL_NORMAL,
	MEXIF_MODEL_PANASONIC_DMC_LC5,	///< makernote endian is big endian.
	MEXIF_MODEL_NIKON_COOLPIX2100,	///< fucking nikon. BUG: PreviewImage offset.
	MEXIF_MODEL_NIKON_COOLPIX3100,  ///< nikon sucks.   BUG: PreviewImage offset.
	MEXIF_MODEL_RICOH_RR120,		///< unknown makernote tag.
	MEXIF_MODEL_RICOH_RDC7S,		///< unknown makernote tag.
	MEXIF_MODEL_MINOLTA_5D,
	MEXIF_MODEL_MINOLTA_7D,
	MEXIF_MODEL_SONY_A100,
	MEXIF_MODEL_SONY_A700,
} mexif_model_t;

typedef enum
{
	MEXIF_LITTLE_ENDIAN,
	MEXIF_BIG_ENDIAN,
} mexif_endian_t;

typedef enum
{
	MEXIF_ROTATE_None,
	MEXIF_ROTATE_90,		///< clockwise rotation.
	MEXIF_ROTATE_180,
	MEXIF_ROTATE_270,
} mexif_rotate_t;

typedef struct
{
    const unsigned char*	data;
    mexif_uint32	        size;
} mexif_thumbnail_t;

typedef struct  
{
	mexif_uint32	id;
	mexif_pcstr		name;
	mexif_pcstr		desc;
} mexif_tagdb_t;

typedef const mexif_tagdb_t* mexif_pctagdb;
typedef mexif_pctagdb (MEXIF_API *mexif_db_search_func)( unsigned int tag );


typedef struct  
{
	mexif_pctagdb			db;
	mexif_uint32			count;
	mexif_db_search_func	func;
} mexif_tagdb_meta_t;

typedef struct
{
	/// given data & size.
	const unsigned char*	data;
	unsigned int			size;

	mexif_maker_t			maker;
	mexif_model_t			model;
	mexif_makernote_t		makernote;
} mexif_exif_core_t;

typedef struct 
{
	mexif_section_type_t	section;
	mexif_format_t			format;
	mexif_endian_t			endian;

	/// where 0 offset begins.
	const unsigned char*	data;
	/// where header begins.
	unsigned int			offset;
	unsigned int			size;
} mexif_ifd_core_t;

/// scanning and retreiving exif tags.
typedef struct
{
	mexif_exif_core_t		core;
	mexif_endian_t			endian;

	mexif_ifd_core_t		ifds[_MEXIF_SECTION_COUNT];
} mexif_exif_t;

typedef struct
{
	mexif_exif_core_t		exif;
	mexif_ifd_core_t		ifd;

	/// tag count inside section.
	mexif_uint32			count;
	const mexif_tagdb_t*	tag_db;
} mexif_section_t;

typedef struct  
{
	mexif_exif_core_t		exif;
	mexif_ifd_core_t		ifd;
	const mexif_tagdb_t*	tag_db_entry;

	const unsigned char*	tag_pointer;
	unsigned int			tag_id;

	mexif_format_t			value_format;
	const unsigned char*	value_pointer;
	unsigned int			value_type;
	unsigned int			value_count;
	unsigned int			value_size;
	unsigned int			value_offset;
} mexif_tag_t;


typedef struct  
{
	/// data begin offset.
	unsigned int			offset;
	/// endian of given data.
	mexif_endian_t			endian;
} mexif_tiffheader_t;

typedef struct
{
	mexif_uint16			year;
	mexif_uint16			month;
	mexif_uint16			date;

	mexif_uint16			hour;
	mexif_uint16			minute;
	mexif_uint16			second;
} mexif_time_t;


#ifdef __cplusplus
}
#endif


#endif // __MEXIF_DEF_H__
